﻿// 602 最小生成树2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <algorithm>
#include <memory.h>

using namespace std;
/*
http://oj.daimayuan.top/course/14/problem/691

给你一张 n个顶点 m条边的无向简单连通图，顶点编号从 1到 n
，每条边都有一个边权，边权为非负整数。

请求出这张图的最小生成树，只需要输出最小生成树的边权和即可。

输入格式
第一行两个整数 n,m，表示图的顶点数、边数。

接下来 m行，每行三个整数 x,y,z
，表示 x号点与 y号点之间有一条边权为 z的边。

数据保证图中顶点两两连通。

输出格式
输出一行一个数，表示最小生成树的边权和。

样例输入
4 4
1 2 1
2 3 3
3 4 1
1 4 2
样例输出
4
数据规模
对于所有数据，保证 2≤n≤50000,n−1≤m≤100000,1≤x,y≤n,1≤z≤10000。
*/

const int N = 50010, M = 200010;
int f[N];
int n, m;

struct Edge {
	int a, b, w;
	bool operator<(const struct Edge& W) {
		return w < W.w;
	}
}edges[M];

int find(int x) {
	if (x != f[x]) f[x] = find(f[x]);
	return f[x];
}

int kruskal() {
	sort(edges, edges + m);
	for (int i = 1; i <= n; i++) f[i] = i;

	int res = 0; int cnt = 0;
	for (int i = 0; i < m; i++) {
		int a = edges[i].a; int b = edges[i].b; int w = edges[i].w;
		a = find(a); b = find(b);
		if (a != b) {
			f[a] = b;
			cnt++; res += w;
		}
	}
	if (cnt < n - 1)return 0x3f3f3f3f;
	return res;
}


int main()
{
	cin >> n >> m;

	for (int i = 0; i < m; i++) {
		int a, b, c; cin >> a >> b >> c;
		edges[i].a = a; edges[i].b = b; edges[i].w = c;
	}

	cout << kruskal() << endl;

	return 0;
}

 